import java.util.ArrayList;
import java.util.Scanner;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class GradeManage {
    final private TreeMap<String,Grade> courses;
    public GradeManage(){
        courses=new TreeMap<>();
    }
    public static void main(String[]args){
        Grade grade=new Grade("Java");
        grade.Add(new Stu(),new DuoGrade());
        grade.Add(new Stu("你好","4","5"),new DuoGrade(60,90));
        grade.show();
        System.out.println("年级/班级平均分"+grade.AverScore());
    }
    public GradeManage AddCourse(String name){
        courses.put(name,new Grade(name));
        return this;
    }
    public GradeManage AddCourseStu(String name,Stu s,DuoGrade duo){
        if(courses.containsKey(name))
            courses.get(name).Add(s,duo);
            // else TODO: 2020/11/8

        return this;
    }
    public void show(){
        courses.forEach((str,grade)->grade.show());
    }
}
class Grade{
    final private String courseName;
    final private ArrayList<Classes> classes;
    public Grade(String name){
        classes=new ArrayList<>();
        this.courseName=name;
    }
    public double getClassAver(final String cid){
        return classes.stream().mapToDouble(e->cid.equals(e.getClassId())?e.AverScore():0).sum();
    }

    public String getCourseName() {
        return courseName;
    }
    public void Add(Stu s,String CID,DuoGrade duo){
        for(Classes c:classes){
            if(c.getClassId().equals(CID)){
                c.Add(s,duo.half,duo.end);
                return;
            }
        }classes.add(new Classes(s,duo));
    }
    public void Add(Stu s,DuoGrade duo){
        this.Add(s,s.getClassID(),duo);
    }
    public void show(){
        System.out.println(courseName+":");
        classes.forEach(e-> System.out.println(e.toString()));
    }
    public double AverScore(){
        return classes.stream().mapToDouble(Classes::AverScore).sum()/classes.size();
    }

    @Override
    public String toString() {
        return "Grade{\n" +
                "courseName='" + courseName + '\'' +
                ", AverageScore=" + this.AverScore() +
                "\n}";
    }
}
class Classes{
    final private ArrayList<Stu> classes;
    final private ArrayList<DuoGrade> score;
    public String getClassId(){
        return classes.get(0).getClassID();
    }
    public double AverScore(){
        return score.stream().mapToDouble(e -> 0.5 * e.half + 0.5 * e.end).sum();
    }
    public Classes(){
        classes=new ArrayList<>();
        score=new ArrayList<>();
    }
    public Classes(Stu s,DuoGrade duo){
        this();
        classes.add(s);
        score.add(duo);
    }
    public void Add(){
        Stu s=new Stu();
        DuoGrade duo=new DuoGrade();
        this.Add(s,duo.half,duo.end);
    }
    public void Add(Stu s,double h,double e){
        classes.add(s);
        score.add(new DuoGrade(h,e));
    }

    @Override
    public String toString() {
        return "Info" + classes + ", \nscore" + score;
    }
}
class DuoGrade{
    public double half;
    public double end;
    public static boolean ScoreOutOfRange(double s){
        return s<0||s>100;
    }
    public DuoGrade(double h,double e)throws RuntimeException{
        if(ScoreOutOfRange(h)|ScoreOutOfRange(e))
            throw new RuntimeException("Score is Out of Range");
        this.half=h;this.end=e;
    }
    public DuoGrade(){
        Scanner scanner=new Scanner(System.in);
//        Pattern ValidScore=Pattern.compile("100|([1-9][0-9]?(\\.[0-9]*[1-9])?)|0");
        do{
            System.out.print("please input your half score(1-100) : ");
            half=scanner.nextDouble();
        }while(half<0||half>100);
        do{
            System.out.print("please input your final score(1-100) : ");
            end=scanner.nextDouble();
        }while(end<0||end>100);
    }

    @Override
    public String toString() {
        return "half=" + half + ", final=" + end;
    }
}
class Stu{
    private String name;
    private String ID;
    private String classID;
    public Stu(String n,String Id,String CID){
        construct(n,Id,CID);
    }
    private void construct(String n, String Id, String CID){
        this.name=n;
        this.ID=Id;
        this.classID=CID;
    }
    public Stu(){
        Scanner scanner=new Scanner(System.in);
        System.out.print("please input your name:");
        String n=scanner.next();
        Pattern pattern=Pattern.compile("[1-9][0-9]*");
        Matcher isNum;
        String Id;
        String cid;
        isNum=pattern.matcher("");
        while(true) {
            System.out.print("please input your Id:");
            Id = scanner.next();
            isNum = pattern.matcher(Id);
            if (isNum.matches()) {
                break;
            } else {
                System.out.println("Wrong stu Id which is not matched");
            }
        }
        while(true){
            System.out.print("please input your class Id(just a number is OK):");
            cid = scanner.next();
            isNum=pattern.matcher(cid);
            if(isNum.matches()){
                break;
            }else{
                System.out.println("Wrong class Id which is not matched");
            }
        }
        construct(n,Id,cid);
    }

    public String getClassID() {
        return classID;
    }

    public String getID() {
        return ID;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "name='" + name + '\'' + ", ID='" + ID;
    }
    public String all(){
        return "name='" + name + '\'' + ", ID='" + ID + ", classID='" + classID;
    }
}